﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using YJKArchMethodLibrary.ColumnProfileAnalyze;
using YJKArchMethodLibrary.GradeLevel;
using YJKRGeometry;
using TopologySearch;

namespace ModelChecking.PerformanceAnalysis.ShapeCoeffiecientOfBuilding
{
	internal class DocumentResultPacker
	{
		public ColumnProfileAnalyzer ColumnProfileAnalyzer { get; set; }

		public Document Doc { get; set; }

		public Dictionary<double, List<Pole2D>> WallAndColumnList { get; set; }

		public Dictionary<double, List<Floor>> FloorList { get; set; }

		public List<Document> LinkDocumentList { get; set; }

		public double GradeLevelElevation { get; set; }

		public DocumentResultPacker(Autodesk.Revit.DB.Document doc, ColumnProfileAnalyzer columnProfileAnalyzer)
		{
			this.Doc = doc;
			this.WallAndColumnList = new Dictionary<double, List<Pole2D>>();
			this.FloorList = new Dictionary<double, List<Floor>>();
			this.LinkDocumentList = new List<Document>();
			this.GradeLevelElevation = -99999.0;
			this.ColumnProfileAnalyzer = columnProfileAnalyzer;
			this.m_EffectiveLevelList = new List<double>();
		}

		public bool GetAllEffectiveLevel()
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.Doc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(ViewPlan));
			IList<Element> list = filteredElementCollector.WherePasses(elementClassFilter).ToElements();
			if (this.GradeLevelElevation == -99999.0)
			{
				return false;
			}
			foreach (Element element in list)
			{
				ViewPlan viewPlan = element as ViewPlan;
				if (viewPlan != null && viewPlan.GenLevel != null && viewPlan.GenLevel != null)
				{
					double elevation = viewPlan.GenLevel.Elevation;
                    if (Geometry.Greaterthan_Or_Equal(elevation, this.GradeLevelElevation) && (int)viewPlan.ViewType == 1 && !this.m_EffectiveLevelList.Contains(elevation))
					{
						this.m_EffectiveLevelList.Add(elevation);
					}
				}
			}
			return true;
		}

		private bool LnkDocListInit()
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.Doc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(RevitLinkInstance));
			IList<Element> list = filteredElementCollector.WherePasses(elementClassFilter).ToElements();
			foreach (Element element in list)
			{
				RevitLinkInstance revitLinkInstance = element as RevitLinkInstance;
				if (revitLinkInstance != null)
				{
					Document linkDocument = revitLinkInstance.GetLinkDocument();
					if (linkDocument != null)
					{
						this.LinkDocumentList.Add(linkDocument);
					}
				}
			}
			return true;
		}

		private bool GradeLevelInit()
		{
			Level gradeLevel = GradeLevelSearch.GetGradeLevel(this.Doc);
			if (gradeLevel == null)
			{
				return false;
			}
			this.GradeLevelElevation = gradeLevel.Elevation;
			return true;
		}

		private bool AddWallToList(Autodesk.Revit.DB.Document doc)
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(Wall));
			IList<Element> list = filteredElementCollector.WherePasses(elementClassFilter).ToElements();
			foreach (Element element in list)
			{
				if (element != null)
				{
					Wall wall = element as Wall;
					ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();
					double num = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
					if (!(null == elementId) && num != -1.7976931348623157E+308)
					{
						this.m_tempLevel = (doc.GetElement(elementId) as Level);
						double num2 = this.m_tempLevel.Elevation + num;
						if (num2 >= this.GradeLevelElevation)
						{
							this.m_levelElevation = this.GetLevelByElevation(num2);
							this.m_tempPole2D = Utility.GetPole2D(wall);
							if (this.m_tempPole2D != null)
							{
								this.AddPole2DToList(this.m_levelElevation, this.m_tempPole2D);
							}
						}
					}
				}
			}
			return true;
		}

		private bool AddColumnToList(Autodesk.Revit.DB.Document doc)
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(FamilyInstance));
			ElementCategoryFilter elementCategoryFilter = new ElementCategoryFilter(BuiltInCategory.OST_Columns);
			ElementCategoryFilter elementCategoryFilter2 = new ElementCategoryFilter(BuiltInCategory.OST_StructuralColumns);
			LogicalOrFilter logicalOrFilter = new LogicalOrFilter(elementCategoryFilter, elementCategoryFilter2);
			IList<Element> list = filteredElementCollector.WherePasses(elementClassFilter).WherePasses(logicalOrFilter).ToElements();
			foreach (Element element in list)
			{
				if (element != null)
				{
					FamilyInstance familyInstance = element as FamilyInstance;
					ElementId elementId = familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).AsElementId();
					double num = familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).AsDouble();
					if (!(null == elementId) && num != -1.7976931348623157E+308)
					{
						this.m_tempLevel = (doc.GetElement(elementId) as Level);
						if (this.m_tempLevel != null)
						{
							double num2 = this.m_tempLevel.Elevation + num;
							if (!Geometry.LessThan(num2, this.GradeLevelElevation))
							{
								this.m_levelElevation = this.GetLevelByElevation(num2);
								this.m_tempPole2Ds = Utility.GetPole2D(this.ColumnProfileAnalyzer, familyInstance);
								if (this.m_tempPole2Ds != null)
								{
									foreach (Pole2D inputPole2D in this.m_tempPole2Ds)
									{
										this.AddPole2DToList(this.m_levelElevation, inputPole2D);
									}
								}
							}
						}
					}
				}
			}
			return true;
		}

		private bool AddPole2DToList(double inputLevel, Pole2D inputPole2D)
		{
			if (this.WallAndColumnList == null)
			{
				return false;
			}
			if (!this.WallAndColumnList.ContainsKey(inputLevel))
			{
				this.WallAndColumnList.Add(inputLevel, new List<Pole2D>());
			}
			this.WallAndColumnList[inputLevel].Add(inputPole2D);
			return true;
		}

		private bool AddFloorToList(Autodesk.Revit.DB.Document doc)
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc);
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(Floor));
			IList<Element> list = filteredElementCollector.WherePasses(elementClassFilter).ToElements();
			foreach (Element element in list)
			{
				if (element != null)
				{
					Floor floor = element as Floor;
					ElementId elementId = floor.get_Parameter(BuiltInParameter.LEVEL_PARAM).AsElementId();
					double num = floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).AsDouble();
					if (!(null == elementId) && num != -1.7976931348623157E+308)
					{
						this.m_tempLevel = (doc.GetElement(elementId) as Level);
						double num2 = this.m_tempLevel.Elevation + num;
						if (num2 >= this.GradeLevelElevation)
						{
							this.m_levelElevation = this.GetLevelByElevation(num2);
							this.AddFloorToList(this.m_levelElevation, floor);
						}
					}
				}
			}
			return true;
		}

		private double GetLevelByElevation(double tempElementElevation)
		{
			int index = -1;
			double num = double.MaxValue;
			for (int i = 0; i < this.m_EffectiveLevelList.Count; i++)
			{
				double num2 = this.m_EffectiveLevelList[i];
				double num3 = Math.Abs(tempElementElevation - num2);
				if (num3 < num)
				{
					num = num3;
					index = i;
				}
			}
			return this.m_EffectiveLevelList[index];
		}

		private bool AddFloorToList(double inputLevel, Floor inputFloor)
		{
			if (this.FloorList == null)
			{
				return false;
			}
			if (!this.FloorList.ContainsKey(inputLevel))
			{
				this.FloorList.Add(inputLevel, new List<Floor>());
			}
			this.FloorList[inputLevel].Add(inputFloor);
			return true;
		}

		public bool Init()
		{
			if (!this.GradeLevelInit())
			{
				return false;
			}
			if (!this.GetAllEffectiveLevel())
			{
				return false;
			}
			if (!this.LnkDocListInit())
			{
				return false;
			}
			this.AddFloorToList(this.Doc);
			this.AddColumnToList(this.Doc);
			this.AddWallToList(this.Doc);
			foreach (Autodesk.Revit.DB.Document doc in this.LinkDocumentList)
			{
				this.AddFloorToList(doc);
				this.AddColumnToList(doc);
				this.AddWallToList(doc);
			}
			List<KeyValuePair<double, List<Floor>>> list = (from k in this.FloorList
			orderby k.Key
			select k).ToList<KeyValuePair<double, List<Floor>>>();
			List<KeyValuePair<double, List<Pole2D>>> list2 = (from k in this.WallAndColumnList
			orderby k.Key
			select k).ToList<KeyValuePair<double, List<Pole2D>>>();
			this.FloorList.Clear();
			for (int i = 0; i < list.Count; i++)
			{
				this.FloorList.Add(list.ElementAt(i).Key, list.ElementAt(i).Value);
			}
			this.WallAndColumnList.Clear();
			for (int j = 0; j < list2.Count; j++)
			{
				this.WallAndColumnList.Add(list2.ElementAt(j).Key, list2.ElementAt(j).Value);
			}
			return true;
		}

		private List<Pole2D> m_tempPole2Ds;

		private Pole2D m_tempPole2D;

		private Level m_tempLevel;

		private double m_levelElevation;

		private List<double> m_EffectiveLevelList;
	}
}
